package eiisan.datatime;

import org.junit.jupiter.api.Test;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.util.Date;

/**
 * @author eii
 * @sice 2020/11/9
 */
public class TimeDemo {
    @Test
    public void testFormat(){
        // 需要对 毫秒进行解析，这样是错误的，需要使用下面DateTimeFormatterBuilder自行构建
        // DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHHmmssS");
        //自行构建
        DateTimeFormatter DATE_TIME_FORMATTER = new DateTimeFormatterBuilder()
                // 解析date+time
                .appendPattern("yyyyMMddHHmmss")
                // 解析毫秒数
                .appendValue(ChronoField.MILLI_OF_SECOND, 3)
                .toFormatter();
        LocalDateTime dt1 = LocalDateTime.parse("20190510134643946", DATE_TIME_FORMATTER);
//2019-05-10T13:46:43.946
        System.out.println(dt1);
//LocalDateTime 转化为Date方法
        ZoneId zoneId = ZoneId.systemDefault();
        ZonedDateTime zdt = dt1.atZone(zoneId);
        Date date0 = Date.from(zdt.toInstant());
//Fri May 10 13:46:43 CST 2019
        System.out.println(date0);

        //根据指定日期/时间创建对象
        LocalDate localDate0  = LocalDate.of(2019, 9, 3);
        LocalTime localTime0  = LocalTime.of(23, 11, 3);
        LocalDateTime localDateTime0 = LocalDateTime.of(2019, 1, 31, 9, 43, 20);
//        2019-09-03
//        23:11:03
//        2019-01-31T09:43:20
        System.out.println(localDate0);
        System.out.println(localTime0);
        System.out.println(localDateTime0);
//        日期时间的加减
//        对于LocalDate,只有精度大于或等于日的加减，如年、月、日；
//        对于LocalTime,只有精度小于或等于时的加减，如时、分、秒、纳秒；
//        对于LocalDateTime,则可以进行任意精度的时间相加减；
        LocalDateTime localDateTime = LocalDateTime.now();
//以下方法的参数都是long型，返回值都是LocalDateTime
        LocalDateTime plusYearsResult = localDateTime.plusYears(2L);
        LocalDateTime plusMonthsResult = localDateTime.plusMonths(3L);
        LocalDateTime plusDaysResult = localDateTime.plusDays(7L);
        LocalDateTime plusHoursResult = localDateTime.plusHours(2L);
        LocalDateTime plusMinutesResult = localDateTime.plusMinutes(10L);
        LocalDateTime plusSecondsResult = localDateTime.plusSeconds(10L);

        System.out.println("当前时间是 : " + localDateTime + "\n"
                + "当前时间加2年后为 : " + plusYearsResult + "\n"
                + "当前时间加3个月后为 : " + plusMonthsResult + "\n"
                + "当前时间加7日后为 : " + plusDaysResult + "\n"
                + "当前时间加2小时后为 : " + plusHoursResult + "\n"
                + "当前时间加10分钟后为 : " + plusMinutesResult + "\n"
                + "当前时间加10秒后为 : " + plusSecondsResult + "\n"
        );
//也可以以另一种方式来相加减日期，即plus(long amountToAdd, TemporalUnit unit)
//                  参数1 ： 相加的数量， 参数2 ： 相加的单位
        LocalDateTime nextMonth = localDateTime.plus(1, ChronoUnit.MONTHS);
        LocalDateTime nextYear = localDateTime.plus(1, ChronoUnit.YEARS);
        LocalDateTime nextWeek = localDateTime.plus(1, ChronoUnit.WEEKS);
        System.out.println("now : " + localDateTime + "\n"
                + "nextYear : " + nextYear + "\n"
                + "nextMonth : " + nextMonth + "\n"
                + "nextWeek :" + nextWeek + "\n"
        );
//        将年、月、日等修改为指定的值，并返回新的日期（时间）对象
//        析： 其效果与时间日期相加减差不多，如今天是2018-01-13，要想变为2018-01-20有两种方式
//        a. localDate.plusDays(20L) -> 相加指定的天数
//        b. localDate.withDayOfYear(20) -> 直接指定到哪一天
        LocalDate localDate = LocalDate.now();
//当前时间基础上，指定本年当中的第几天，取值范围为1-365,366
        LocalDate withDayOfYearResult = localDate.withDayOfYear(200);
//当前时间基础上，指定本月当中的第几天，取值范围为1-29,30,31
        LocalDate withDayOfMonthResult = localDate.withDayOfMonth(5);
//当前时间基础上，直接指定年份
        LocalDate withYearResult = localDate.withYear(2017);
//当前时间基础上，直接指定月份
        LocalDate withMonthResult = localDate.withMonth(5);
        System.out.println("当前时间是 : " + localDate + "\n"
                + "指定本年当中的第200天 : " + withDayOfYearResult + "\n"
                + "指定本月当中的第5天 : " + withDayOfMonthResult + "\n"
                + "直接指定年份为2017 : " + withYearResult + "\n"
                + "直接指定月份为5月 : " + withMonthResult + "\n");

//        获取日期的年月日周时分秒
        LocalDateTime localDateTime2 = LocalDateTime.now();
        int dayOfYear = localDateTime2.getDayOfYear();
        int dayOfMonth = localDateTime2.getDayOfMonth();
        DayOfWeek dayOfWeek = localDateTime2.getDayOfWeek();
        System.out.println("今天是" + localDateTime2 + "\n"
                + "本年当中第" + dayOfYear + "天" + "\n"
                + "本月当中第" + dayOfMonth + "天" + "\n"
                + "本周中星期" + dayOfWeek.getValue() + "-即" + dayOfWeek + "\n");

        //获取当天时间的年月日时分秒
        int year = localDateTime.getYear();
        Month month = localDateTime.getMonth();
        int day = localDateTime.getDayOfMonth();
        int hour = localDateTime.getHour();
        int minute = localDateTime.getMinute();
        int second = localDateTime.getSecond();
        System.out.println("今天是" + localDateTime + "\n"
                + "年 ： " + year + "\n"
                + "月 ： " + month.getValue() + "-即 "+ month + "\n"
                + "日 ： " + day + "\n"
                + "时 ： " + hour + "\n"
                + "分 ： " + minute + "\n"
                + "秒 ： " + second + "\n"
        );

//时间日期前后的比较与判断
//判断两个时间点的前后
        LocalDate localDate1 = LocalDate.of(2017, 8, 8);
        LocalDate localDate2 = LocalDate.of(2018, 8, 8);
        boolean date1IsBeforeDate2 = localDate1.isBefore(localDate2);
        System.out.println("date1IsBeforeDate2 : " + date1IsBeforeDate2);
//        判断是否为闰年
        LocalDate now = LocalDate.now();
        System.out.println("now : " + now + ", is leap year ? " + now.isLeapYear());

//java8时钟 ： clock()
//返回当前时间，根据系统时间和UTC
        Clock clock = Clock.systemUTC();
// 运行结果： SystemClock[Z]
        System.out.println(clock);

//        时间戳
//        事实上Instant就是java8以前的Date，
//        可以使用以下两个类中的方法在这两个类型之间进行转换，
//        比如Date.from(Instant)就是用来把Instant转换成java.util.date的，
//        而new Date().toInstant()就是将Date转换成Instant的

        Instant instant = Instant.now();
//2020-09-03T06:59:26.508Z
        System.out.println(instant);
        Date date = Date.from(instant);
        Instant instant2 = date.toInstant();
//Thu Sep 03 14:59:26 CST 2020
        System.out.println(date);
//2020-09-03T06:59:26.508Z
        System.out.println(instant2);

//        计算时间、日期间隔
//        Duration:用于计算两个“时间”间隔
//        Period:用于计算两个“日期”间隔

//计算两个日期的日期间隔-年月日
        LocalDate date1 = LocalDate.of(2018, 2, 13);
        LocalDate date2 = LocalDate.of(2017, 3, 12);
//内部是用date2-date1，所以得到的结果是负数
        Period period = Period.between(date1, date2);
        System.out.println("相差年数 ： " + period.getYears());
        System.out.println("相差月数 ： " + period.getMonths());
        System.out.println("相差日数 ： " + period.getDays());
//还可以这样获取相差的年月日
        System.out.println("-------------------------------");
        long years = period.get(ChronoUnit.YEARS);
        long months = period.get(ChronoUnit.MONTHS);
        long days = period.get(ChronoUnit.DAYS);
        System.out.println("相差的年月日分别为 ： " + years + "," + months + "," + days);
//注意，当获取两个日期的间隔时，并不是单纯的年月日对应的数字相加减，而是会先算出具体差多少天，在折算成相差几年几月几日的

//计算两个时间的间隔
        System.out.println("-------------------------------");
        LocalDateTime date3 = LocalDateTime.now();
        LocalDateTime date4 = LocalDateTime.of(2018, 1, 13, 22, 30, 10);
        Duration duration = Duration.between(date3, date4);
        System.out.println(date3 + " 与 " + date4 + " 间隔  " + "\n"
                + " 天 :" + duration.toDays() + "\n"
                + " 时 :" + duration.toHours() + "\n"
                + " 分 :" + duration.toMinutes() + "\n"
                + " 毫秒 :" + duration.toMillis() + "\n"
                + " 纳秒 :" + duration.toNanos() + "\n"
        );
//注意，并没有获得秒差的，但既然可以获得毫秒，秒就可以自行获取了

//当计算程序的运行时间时，应当使用时间戳Instant

        Instant ins1 = Instant.now();
        for (int i = 0; i < 10000000; i++) {
            //循环一百万次
        }
        Instant ins2 = Instant.now();
        Duration duration2 = Duration.between(ins1, ins2);
        System.out.println("程序运行耗时为 ： " + duration2.toMillis() + "毫秒");

//时间日期的格式化（格式化后返回的类型是String）
//1. 使用jdk自身配置好的日期格式
//使用jdk自身配置好的日期格式
        DateTimeFormatter formatter1 = DateTimeFormatter.ISO_DATE_TIME;
        LocalDateTime date31 = LocalDateTime.now();
//反过来调用也可以 : date1.format(formatter1);
        String date1Str = formatter1.format(date31);
        System.out.println(date1Str);

//2. 使用自定义格式
        DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
        String date2Str = formatter2.format(date31);
        System.out.println(date2Str);
//注：自定义转化的格式一定要与日期类型对应
//LocalDate只能设置仅含年月日的格式
// LocalTime只能设置仅含时分秒的格式
//LocalDateTime可以设置含年月日时分秒的格式
        DateTimeFormatter formatter3 = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        System.out.println(formatter3.format(LocalDate.now()));

        System.out.println("-------------------------------");

        DateTimeFormatter formatter4 = DateTimeFormatter.ofPattern("HH:mm:ss");
        System.out.println(formatter4.format(LocalTime.now()));
//将时间字符串形式转化为日期对象
        String datetime =  "2018-01-13 21:27:30";
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime ldt = LocalDateTime.parse(datetime, dtf);
        System.out.println(ldt);
//        注：格式的写法必须与字符串的形式一样
//        2018-01-13 21:27:30 对应 yyyy-MM-dd HH:mm:ss
//        20180113213328 对应 yyyyMMddHHmmss
//        否则会报运行时异常！
//        但要记住：得到的最终结果都是类似2018-01-13T21:27:30的格式
//        因为在输出LocalDateTime对象时，会调用其重写的toString方法。
/*        @Override
        public String toString() {
            return date.toString() + 'T' + time.toString();
        }*/

//将时间日期对象转为格式化后的时间日期对象
//新的格式化API中，格式化后的结果都默认是String，有时我们也需要返回经过格式化的同类型对象
        LocalDateTime ldt1 = LocalDateTime.now();
        DateTimeFormatter dtf1 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String temp = dtf1.format(ldt1);
        //2020-09-03 15:41:06
        System.out.println(temp);
        LocalDateTime formatedDateTime = LocalDateTime.parse("2020-09-03 15:43:06", dtf1);
        //2020-09-03T15:43:06
        System.out.println(formatedDateTime);

//long毫秒值转换为日期
        System.out.println("---------long毫秒值转换为日期---------");
        DateTimeFormatter df= DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String longToDateTime = df.format(LocalDateTime.ofInstant(
                Instant.ofEpochMilli(System.currentTimeMillis()),ZoneId.of("Asia/Shanghai")));
        System.out.println(longToDateTime);
    }
}
